package com.siyu.predict.utils;

import java.util.ArrayList;
import java.util.List;

/**
 * 算法工具类
 */
public class AlgorithmUtil {
    /**
     * nash系数计算
     * @param preQ 预测流量
     * @param relQ 实测流量
     * @return
     */
    public static Double calcNash(List<Double> preQ, List<Double> relQ) {
        // 计算Oavg，realData中元素的平均值
        Double sum = 0.0;
        for (Double value : relQ) {
            sum += value;
        }
        Double oAvg = sum / relQ.size();
        // 计算Σ(Oi - Si)² 和 Σ(Oi - Oavg)²
        Double diffSum = 0.0;
        Double avgDiffSum = 0.0;
        for (int i = 0; i < preQ.size(); i++) {
            Double oi = relQ.get(i);
            Double si = preQ.get(i);
            diffSum += Math.pow(oi - si, 2);
            avgDiffSum += Math.pow(oi - oAvg, 2);
        }
        // 计算Nash系数并返回结果
        Double nash = 1 - (diffSum / avgDiffSum);
        return nash;
    }

    /**
     * 不确定系数计算
     * @param preData
     * @param realData
     * @return
     */
    public static Double calculateGUC(List<Double> preData, List<Double> realData) {
        // 计算Savg，preData中元素的平均值
        Double sumS = 0.0;
        for (Double value : preData) {
            sumS += value;
        }
        Double sAvg = sumS / preData.size();
        // 计算Oavg，realData中元素的平均值
        Double sumO = 0.0;
        for (Double value : realData) {
            sumO += value;
        }
        Double oAvg = sumO / realData.size();
        // 计算Σ(Si - Oi)²，Σ(Si - Savg)² 和 Σ(Oi - Oavg)²
        Double siMinusOiSum = 0.0;
        Double siMinusSAvgSum = 0.0;
        Double oiMinusOAvgSum = 0.0;
        for (int i = 0; i < preData.size(); i++) {
            Double si = preData.get(i);
            Double oi = realData.get(i);
            siMinusOiSum += Math.pow(si - oi, 2);
            siMinusSAvgSum += Math.pow(si - sAvg, 2);
            oiMinusOAvgSum += Math.pow(oi - oAvg, 2);
        }
        // 计算GUC系数并返回结果
        Double guc = 1 - (siMinusOiSum / (siMinusSAvgSum + oiMinusOAvgSum));
        return guc;
    }



    /**
     * 确定系数计算
     * @param preData 预测数据
     * @param realData 实测数据
     * @return
     */
    public static double calculateRSquared(List<Double> preData, List<Double> realData) {
        // 计算实测数据的平均值
        double avgRealData = calculateAverage(realData);

        // 计算总平方和 TSS
        double tss = 0.0;
        for (double real : realData) {
            tss += Math.pow(real - avgRealData, 2);
        }

        // 计算残差平方和 RSS
        double rss = 0.0;
        for (int i = 0; i < realData.size(); i++) {
            double residual = realData.get(i) - preData.get(i);
            rss += Math.pow(residual, 2);
        }

        // 计算确定系数 R^2
        double rSquared = 1 - (rss / tss);
        return rSquared;
    }

    // 平均值计算
    public static double calculateAverage(List<Double> data) {
        double sum = 0.0;
        for (double value : data) {
            sum += value;
        }
        return sum / data.size();
    }

}
